#include <bits/stdc++.h>
using namespace std;
const int NMAX = 30;
int G[NMAX][NMAX];
int n, e, ans;
int S[NMAX]; //   判断第i个点是否在S集合中。

/*
深搜(回溯)dfs：要将无向图的顶点分为两个集合S、T，求跨过割的最大边数(边权和)。
last表示选中最近放入S中，  cnt当前的割边数量， depth当前深度，
*/

void dfs(int last, int cnt, int depth) {
  /*
  若点x新加入在S内，则num + G[last][i](i在T内) - G[last][j](j在S内)
  */

  for (int i = 1; i <= n; i++) {
    if (S[i])
      cnt -= G[last][i]; // 在S内
    else
      cnt += G[last][i]; // 在T内
  }

  ans = max(ans, cnt);

  if (depth >= n)// n个点都已考虑完
    return; 

  // 由于 {1,2},{3,4,5} 和 {3,4,5},{1,2}是同一种划分方式，因此我们只需要枚举最多n/2个点的集合即可.
  for (int i = last + 1; i <= n; i++) {
    S[i] = 1;
    dfs(i, cnt, depth + 1);
    S[i] = 0;
  }
}
int main() {

  ios::sync_with_stdio(false);
  cin.tie(0);
  cin >> n >> e;
  for (int i = 1; i <= e; i++) {
    int a, b;
    cin >> a >> b;
    G[a][b]++, G[b][a] = G[a][b]; // 化为边权，无向边
  }
  S[1] = 1; // 考虑将点1放入S
  dfs(1, 0, 1);
  // 从第一点开始， sum一开始为0，  S集合中1个点。
  cout << ans;
  return 0;
}